﻿using M.Core.RmoteCall.Attributes;
using M.Core.Utils;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Routing;
using Newtonsoft.Json;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;

namespace M.Core.RmoteCall.ApiCall
{
    public class HttpApiCallHandler : ICallHandler
    {
        public class CallModel
        {
            public string AppName { get; set; }
            public string Path { get; set; }
            public Type ReturnType { get; set; }
            public bool IsReturnString { get; set; }
            public String Method { get; set; }
            public String CallType { get; set; }
            public float Version { get; set; }
        }
        ConcurrentDictionary<int, CallModel> map = new ConcurrentDictionary<int, CallModel>();

        public object Process(Type type, MethodInfo targetMethod, object[] args)
        {
            

            CallModel callModel = null;
            map.TryGetValue(targetMethod.MetadataToken, out callModel);

            
            if (callModel == null)
            {
                AppInfoAttribute appInfo = ((AppInfoAttribute)type.GetCustomAttribute(typeof(AppInfoAttribute)));

                callModel = new CallModel();

                callModel.AppName = appInfo.Name;
                callModel.Version = appInfo.Version;
                callModel.ReturnType = targetMethod.ReturnType;
                callModel.IsReturnString = callModel.ReturnType.Name.Equals("String");


                var httpApi = ((HttpApiAttribute)targetMethod.GetCustomAttribute(typeof(HttpApiAttribute)));
                if (httpApi != null)
                {
                    callModel.CallType = "HttpApi";
                    callModel.Path = httpApi.Path;
                    var md = targetMethod.GetCustomAttribute(typeof(HttpMethodAttribute));
                    callModel.Method = "GET";
                    if (md != null)
                    {
                        if (md is HttpGetAttribute)
                        {
                            callModel.Method = "GET";
                        }
                        else if (md is HttpPostAttribute)
                        {
                            callModel.Method = "POST";
                        }
                    }
                }

                map.TryAdd(targetMethod.MetadataToken, callModel);
            }



            var json = string.Empty;
            var host = string.Empty;

            IDictionary<ParameterInfo, object> dic = new Dictionary<ParameterInfo, object>();

            var pas = targetMethod.GetParameters();
            for (int i = 0; i < pas.Length; i++)
            {
                var item = pas[i];
                if (args.Length >= i)
                {
                    dic[item] = args[i];
                }
            }

            var hostInfo = ServiceDiscovery.GetInstance().GetHostByRoll(callModel.AppName, callModel.Version);


            var url = $"http://{hostInfo.Address}:{hostInfo.Port}/{callModel.Path}";

            var querys = dic.Count == 0 ? string.Empty : string.Join("&", dic.Select((KeyVal, v) => $"{KeyVal.Key.Name}={(KeyVal.Key.ParameterType.Name.Equals("String") ? KeyVal.Key.Name : JsonConvert.SerializeObject(KeyVal.Value))}"));


            json = CallStrategy.GetInstance().InvokeApi(type, targetMethod, callModel.Method, url, querys);


            if (callModel.IsReturnString)
            {
                return json;
            }

            return JsonConvert.DeserializeObject(json, callModel.ReturnType);
        }
    }
}
